using System;

// XNA Libs
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Input;


namespace OakEngine.Input
{

    public enum MouseButtons { LeftButton, MiddleButton, RightButton, ExtraButton1, ExtraButton2 }


    /// <summary>
    /// This is a game component that implements IUpdateable.
    /// </summary>
    /// 
    public class OAK_InputManager : Microsoft.Xna.Framework.GameComponent, OAK_IInput
    {

        // Member varaibles
        protected KeyboardState m_KeyState;
        protected KeyboardState m_prevKeys;

        protected GamePadState[] m_GamePads = new GamePadState[4];
        protected GamePadState[] m_prevGamePads = new GamePadState[4];



#if (!XBOX)

        protected MouseState m_MouseState;
        protected MouseState m_prevMouse;
#endif



        public OAK_InputManager(Game game)
            : base(game)
        {
            // TODO: Construct any child components here
            game.Services.AddService(typeof(OAK_IInput), this);

#if (!XBOX)
            Game.IsMouseVisible = true;
            m_prevMouse = Mouse.GetState();
#endif


            m_prevKeys = Keyboard.GetState();
            m_prevGamePads[0] = GamePad.GetState(PlayerIndex.One);
            m_prevGamePads[1] = GamePad.GetState(PlayerIndex.Two);
            m_prevGamePads[2] = GamePad.GetState(PlayerIndex.Three);
            m_prevGamePads[3] = GamePad.GetState(PlayerIndex.Four);

        }

        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        public override void Initialize()
        {
           


            base.Initialize();
        }

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            // Mouse states
            m_prevMouse = m_MouseState;
            m_MouseState = Mouse.GetState();

            // Init Keyboard states
            m_prevKeys = m_KeyState;
            m_KeyState = Keyboard.GetState();

            // Game Pad State
            m_prevGamePads[0] = m_GamePads[0];
            m_prevGamePads[1] = m_GamePads[1];
            m_prevGamePads[2] = m_GamePads[2];
            m_prevGamePads[3] = m_GamePads[3];
            m_GamePads[0] = GamePad.GetState(PlayerIndex.One);
            m_GamePads[1] = GamePad.GetState(PlayerIndex.Two);
            m_GamePads[2] = GamePad.GetState(PlayerIndex.Three);
            m_GamePads[3] = GamePad.GetState(PlayerIndex.Four);
            base.Update(gameTime);
        }

        
        /*******************************
         * Helper Methods 
         *******************************/

        #region Helper Methods

        // Detect Button Press, example: just one button click call

        /// <summary>
        /// Detect Button pressed from a gamepad
        /// </summary>
        /// <param name="button">The button pressed</param>
        /// <param name="index">What controller {0=1}{1=2}{2=3}{3=4}</param>
        /// <returns></returns>
        public bool Pressed(Buttons button, int index)
        {
            return (m_GamePads[index].IsButtonDown(button) && m_prevGamePads[index].IsButtonUp(button));
        }

        /// <summary>
        /// Keyboard Press key
        /// </summary>
        /// <param name="key">the Keys</param>
        /// <returns>If keyboard was prressed</returns>
        public bool Pressed(Keys key)
        {
            return (m_prevKeys.IsKeyUp(key) && m_KeyState.IsKeyDown(key));
        }

        /// <summary>
        /// Detect Mouse Button Pressed
        /// </summary>
        /// <param name="button">A enum State for Button PRess</param>
        /// <returns>If the a certain click was pressed</returns>
        public bool Pressed(MouseButtons button)
        {
            switch (button)
            {
                case MouseButtons.LeftButton:
                    return (m_prevMouse.LeftButton == ButtonState.Released && m_MouseState.LeftButton == ButtonState.Pressed);
                case MouseButtons.MiddleButton:
                    return (m_prevMouse.MiddleButton == ButtonState.Released && m_MouseState.MiddleButton == ButtonState.Pressed);
                case MouseButtons.RightButton:
                    return (m_prevMouse.RightButton == ButtonState.Released && m_MouseState.RightButton == ButtonState.Pressed);
                case MouseButtons.ExtraButton1:
                    return (m_prevMouse.XButton1 == ButtonState.Released && m_MouseState.XButton1 == ButtonState.Pressed);
                case MouseButtons.ExtraButton2:
                    return (m_prevMouse.XButton2 == ButtonState.Released && m_MouseState.XButton2 == ButtonState.Pressed);
                default:
                    return false;
            }
        }

        // Detect Button Down, Example: If you hold down button then call everytime

        /// <summary>
        /// Detect if the game pad Button is held down
        /// </summary>
        /// <param name="button">button that is being held down</param>
        /// <param name="index">What controller {0=1}{1=2}{2=3}{3=4}</param>
        /// <returns>if the button is held down</returns>
        public bool HeldDown(Buttons button, int index)
        {
            return (m_GamePads[index].IsButtonDown(button) && m_prevGamePads[index].IsButtonDown(button));
        }

        /// <summary>
        /// Detect if the Key is held down
        /// </summary>
        /// <param name="key">the key that is being held down</param>
        /// <returns>if the key is down</returns>
        public bool HeldDown(Keys key)
        {
            return (m_prevKeys.IsKeyDown(key) && m_KeyState.IsKeyDown(key));
        }

        /// <summary>
        /// Detect what mouse button is held down
        /// </summary>
        /// <param name="button">the mouse button being held down</param>
        /// <returns>what button is being held down and if it is</returns>
        public bool HeldDown(MouseButtons button)
        {
            switch (button)
            {
                case MouseButtons.LeftButton:
                    return (m_prevMouse.LeftButton == ButtonState.Pressed && m_MouseState.LeftButton == ButtonState.Pressed);
                case MouseButtons.MiddleButton:
                    return (m_prevMouse.MiddleButton == ButtonState.Pressed && m_MouseState.MiddleButton == ButtonState.Pressed);
                case MouseButtons.RightButton:
                    return (m_prevMouse.RightButton == ButtonState.Pressed && m_MouseState.RightButton == ButtonState.Pressed);
                case MouseButtons.ExtraButton1:
                    return (m_prevMouse.XButton1 == ButtonState.Pressed && m_MouseState.XButton1 == ButtonState.Pressed);
                case MouseButtons.ExtraButton2:
                    return (m_prevMouse.XButton2 == ButtonState.Pressed && m_MouseState.XButton2 == ButtonState.Pressed);
                default:
                    return false;
            }
        } 
        #endregion


        #region GamePad Methods

        // Game pad stuff
        public Vector2 LeftStickPosition(int index)
        {
            return new Vector2(m_GamePads[index].ThumbSticks.Left.X, -m_GamePads[index].ThumbSticks.Left.Y);

        }

        public Vector2 RightStickPosition(int index)
        {
            return new Vector2(m_GamePads[index].ThumbSticks.Right.X, -m_GamePads[index].ThumbSticks.Right.Y);
        }

        public Vector2 LeftStickVelocity(int index)
        {
            Vector2 tempVel = m_GamePads[index].ThumbSticks.Left - m_prevGamePads[index].ThumbSticks.Left;

            return new Vector2(tempVel.X, -tempVel.Y);
        }

        public Vector2 RightStickVelocity(int index)
        {
            Vector2 tempVel = m_GamePads[index].ThumbSticks.Right - m_prevGamePads[index].ThumbSticks.Right;

            return new Vector2(tempVel.X, -tempVel.Y);
        }

        public float LeftTriggerPosition(int index)
        {
            return m_GamePads[index].Triggers.Left;
        }

        public float RightTriggerPosition(int index)
        {
            return m_GamePads[index].Triggers.Right;
        }

        public float LeftTriggerVelocity(int index)
        {
            return m_GamePads[index].Triggers.Left - m_prevGamePads[index].Triggers.Left;
        }

        public float RightTriggerVelocity(int index)
        {
            return m_GamePads[index].Triggers.Right - m_prevGamePads[index].Triggers.Right;
        }
        #endregion

        #region Mouse Methods

        public Vector2 MousePosition
        {
            get
            {
                return new Vector2(m_MouseState.X, m_MouseState.Y);
            }
        }

        public Vector2 MouseVelocity
        {
            get
            {
                return (new Vector2(m_MouseState.X,m_MouseState.Y) - new Vector2(m_prevMouse.X,m_prevMouse.Y));
            }
        }

        public float MouseScrollPosition
        {
            get
            {
                return m_MouseState.ScrollWheelValue;
            }
        }

        public float MouseScrollVelocity
        {
            get
            {
                return (m_MouseState.ScrollWheelValue - m_prevMouse.ScrollWheelValue);
            }
        }


        #endregion


        #region Defin Interface
        // Keyboard state and Previous State
        public KeyboardState KeyBoardState
        {
            get
            {
                return (m_KeyState);
            }
        }
        public KeyboardState PreviousKeyState
        {
            get
            {
                return (m_prevKeys);
            }
        }

        // Mouse State and Previous
        public MouseState MouseState
        {
            get
            {
                return (m_MouseState);
            }
        }
        public MouseState PreviousMouseState
        {
            get
            {
                return (m_prevMouse);
            }
        }

        // GamePadState
        public GamePadState[] GamePads
        {
            get
            {
                return (m_GamePads);
            }
        }
        public GamePadState[] PreviousGamePads
        {
            get
            {
                return (m_prevGamePads);
            }
        }

        #endregion

    }
}
